package net.iceflow.dunsel.example.client;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterException;

import java.io.PrintStream;
import net.iceflow.dunsel.client.ClientFacade;
import net.iceflow.dunsel.client.listener.DisconnectionListener;
import net.iceflow.dunsel.client.listener.FailedConnectionListener;
import net.iceflow.dunsel.client.listener.SuccessfulConnectionListener;
import net.iceflow.dunsel.commons.Event;
import net.iceflow.dunsel.example.client.model.dto.Arguments;

/**
 * Simple example Application.
 */
public class Client implements Runnable, SuccessfulConnectionListener, DisconnectionListener, FailedConnectionListener {

    /**
     * Command line arguments.
     */
    private final Arguments _arguments;

    private final String[] _args;

    /**
     * Main application thread.
     */
    private Thread _mainThread;

    /**
     * JCommander argument parser.
     */
    private JCommander _commander;

    /**
     * Main program start entry point.
     * @param args Application arguments
     */
    public static void main(String[] args) {
        Client app = new Client(args);
        app.run();
    }

    /**
     * Constructs a new Client instance.
     * @param arguments
     */
    public Client(final String[] args) {
        this._args = args;
        this._arguments = new Arguments();
        this._commander = new JCommander(this._arguments);
    }

    /**
     * Run entry point.
     */
    @Override
    public void run() {

        this.outputStartupBanner(System.out);

        boolean successfullyParsed = true;

        try {
            this._commander.parse(this._args);
        } catch (ParameterException ex) {
            successfullyParsed = false;
        }

        if (!this._arguments.isUsageHelp() && successfullyParsed && this._arguments.validate()) {
            this.attemptExecution();
        } else {
            this._commander.usage();
        }
    }

    /**
     * Attempts to run main operations of the program.
     */
    private void attemptExecution() {

        this._mainThread = Thread.currentThread();

        String address = this._arguments.getHost();
        ClientFacade facade = ClientFacade.Builder.build();
        facade.getSuccessfulConnectionSubscriptions().addListener(this);
        facade.getDisconnectionSubscriptions().addListener(this);
        facade.getFailedConnectionSubscriptions().addListener(this);

        facade.connect(address, 4776);

        boolean keepLooping = true;

        while (keepLooping) {
            try {
                Thread.sleep(500000);
            } catch (InterruptedException ex) {
                System.out.println("Thread interrupted.");
                keepLooping = false;
            }
        }

        facade.unsubscribeAll();
        this.cleanUp();
    }

    private void cleanUp() {
        this._mainThread = null;
    }

    @Override
    public void onConnectionSucceeded(Event<ClientFacade> e) {
        System.out.println("Connection success!");
    }

    @Override
    public void onConnectionFailed(Event<ClientFacade> e) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void onDisconnected(Event<ClientFacade> e) {
        System.out.println("Disconnect signalled!");
        this._mainThread.interrupt();
    }

    private void outputStartupBanner(PrintStream ps) {
        ps.println();
        ps.println("-------------------------------------------------------------------------------");
        ps.println("-- Dunsel Client Example                                                     --");
        ps.println("-------------------------------------------------------------------------------");
    }
}


